package com.cskaoyan.javase.oop2._1extend._8override;

/**
 * @description: 方法的覆盖/重写
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 方法的覆盖/重写: 父子类中出现同名的成员方法,子类中同名方法会覆盖掉父类中的实现
 *
 * 为什么方法不是隐藏而是覆盖?
 * 通过一个父类调用自身同名方法的方法,我们发现方法如果同名会被覆盖而不是隐藏
 *
 * 创建对象的方式三种:
 *      a,创建父类对象,然后用父类引用接收
 *      b,创建子类对象,然后用子类引用接收
 *      c,创建子类对象,然后用父类引用接收
 * 对象名点访问成员方法的访问范围:
 *      a,父类中有的成员方法
 *      b,父子类都可以
 *      c,仍然是父类
 *    以上,总结规律:
 *            对象名点访问成员变量的范围,和引用的数据类型有关,和对象无关
 *            如果引用是父类类型那么只能访问父类中存在的成员变量
 *            如果引用是子类类型,那么父子类成员变量都可以访问
 *    对象名点调用成员方法,编译器存在如下检索机制:
 *       先从引用的数据类型中去找到该成员变量,如果找不到就先去父类中找,如果找到Object都找不到,那么就会报错
 *
 * 对象名点访问成员方法的调用结果:
 *      a,父类的行为
 *      b,子类的行为
 *      c,子类的行为
 *  以上,对象名点调用方法,结果是引用所指向的具体的对象的类型来决定的,和引用的类型无关
 *  方法的调用机制: 方法在编译器决定访问范围时,是根据引用来决定的,但是方法在调用时,必须要程序运行起来,然后根据对象的具体类型来决定方法的调用结果
 *
 *  注意事项:
 *        1,方法的覆盖不是物理意义上的覆盖,我们仍然可以使用super关键字去调用同名的成员方法
 *              前提是有访问权限
 *        2,静态的成员方法虽然可能出现父子类同名情况,但是实际上是两个独立的静态方法恰好同名了,它们之间没有关系,也不是方法的重写
 *        3,方法重写的快捷键和快捷方式:
 *          1,直接在子类中写父类成员方法的名字,出现提示后,回车即可
 *          2,快捷键alt+insert
 *        4,@Override注解在方法的重写中非常重要,可以帮助我们检测语法,避免错误.其次还可以显著提升代码可读性
 *
 *        5,思考: 哪些方法不能重写?
 *              1,静态方法
 *              2,构造方法,不能被继承更不能重写
 *              3,私有方法,虽然继承了但是没有权限也不能重写
 *
 *
 * 方法的覆盖的语法:
 *      成员方法的语法:
 *      [访问权限修饰符] 返回值类型 方法名(形参){
 *          //方法体
 *      }
 *      方法的重载(overload) vs 方法的重写(override)
 *      相同点:
 *          1,都要求两个方法的方法名一致
 *          2,都对方法体的书写没有要求
 *       不同点:
 *          1,重载对访问权限修饰符没有要求,但是重写是有要求的,必须要求子类方法的访问权限大于等于父类方法
 *          2,重载对返回值类型没有要求,但是重写是有要求的,方法的重写要求子类方法的返回值类型必须和父类方法的返回值类型" 兼容 "(今晚的作业测试一下)
 *          3,重载要求形参必须不一样,但是重写中形参必须完全一致
 *          4,重载必须在同类中,重写必须在父子类中
 *          5,多个方法都可以构成方法重载,但是重写肯定是两个方法
 *
 * 方法的覆盖中,可以使用一个注解来检验是否为合法的方法重写,叫做@Override
 * 它可以放在子类重写方法的头上,检测是否为合法的子类重写方法
 *
 *
 */
public class Demo {
    public static void main(String[] args) {
        /*Son s = new Son();
        s.test();
        s.testMethod();*/

        /*Father f = new Father();
        f.test();
        Son s = new Son();
        s.test();
        Father fs = new Son();
        fs.test();*/

        Son s = new Son();
        s.testSonMethod();

    }
}

class Father {
    void test() {
        System.out.println("father same name");
    }

    /*public void testMethod(){
        test();
    }*/

    public void testFather() {
        System.out.println("father only");
    }

    public static void testStatic() {
        System.out.println("father static");
    }
}

class Son extends Father {
    //Method does not override method from its superclass
    @Override
    void test() {
        System.out.println("son same name");
    }

    public void testSon() {
        System.out.println("son only");
    }

    public void testSonMethod() {
        super.test();
    }

    //Method does not override method from its superclass
    //@Override
    public static void testStatic() {
        System.out.println("son static");
    }


    //两种方式,快速重写父类方法
    //1,直接在子类中写父类成员方法的名字,出现提示后,回车即可
    //2,快捷键alt+insert

    @Override
    public void testFather() {
        super.testFather();
    }

    /*@Override
    public void testFather() {
        super.testFather();
    }*/
}